package com.momoda.monitor.service;


import com.momoda.monitor.bean.FileInfo;
import com.momoda.monitor.bean.FileMetaInfo;
import com.momoda.monitor.config.MonitorFtpFolder;
import com.momoda.monitor.util.FastJsonUtils;
import com.momoda.monitor.util.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.HiddenFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 文件变化监听器
 * <p>
 * 在Apache的Commons-IO中有关于文件的监控功能的代码. 文件监控的原理如下：
 * 由文件监控类FileAlterationMonitor中的线程不停的扫描文件观察器FileAlterationObserver，
 * 如果有文件的变化，则根据相关的文件比较器，判断文件时新增，还是删除，还是更改。（默认为1000毫秒执行一次扫描）
 */
@Slf4j
@EnableConfigurationProperties(MonitorFtpFolder.class)
public class FileListener extends FileAlterationListenerAdaptor {

    public static final String InfoFile = "D:\\SFTP\\info.json";

    @Autowired
    MonitorFtpFolder monitorFtpFolder;


    /**
     * 文件创建执行
     */
    @Override
    public void onFileCreate(File file) {
        log.info("[新建文件]: {}", file.getAbsolutePath());
        log.info(file.getParent());


        //设置文件信息
        String absolutePath = file.getAbsolutePath().replaceAll("\\\\", "/");
        String time = String.valueOf(file.lastModified());
        String md5 = "";
        try {
            md5 = DigestUtils.md5Hex(new FileInputStream(file));
        } catch (IOException e) {
            e.printStackTrace();
            log.error("计算MD5值异常：{}", e.getMessage());
        }

        String exist = "1";
        FileInfo fileinfo = new FileInfo(absolutePath, time, md5, exist);

        //根据路径生成info配置文件，路径不匹配则在根目录生成
        FileUtil fileUtil = FileUtil.getFileUtil();
        File infoFile = fileUtil.generateInfoFile(absolutePath);

        try {
            // 1. 读取配置文件
            FileMetaInfo metaInfo = FileUtil.readInfoFileToBean(infoFile);

            // 2. 判断是否有此配置文件

            List<FileInfo> createFile = metaInfo.getCreateFile();
            if (createFile == null) {
                createFile = new ArrayList<>();
            }
            createFile.add(fileinfo);
            metaInfo.setCreateFile(createFile);
//            for (int i = 0, length = createFile.size(); i < length; i++) {
////                if (absolutePath.equals(createFile.get(i))) { }
//                createFile.add(fileinfo);
//            }


            removeChangeFile(absolutePath, metaInfo);

            removeDeleteFile(absolutePath, metaInfo);

            // 3. 修改并写入json文件

            String json = FastJsonUtils.convertObjectToJSON(metaInfo);
            FileUtils.write(infoFile, json, Charset.forName("utf-8"));

        } catch (IOException e) {
            e.printStackTrace();
        }


    }


    /**
     * 文件创建修改
     */
    @Override
    public void onFileChange(File file) {
        log.info("[修改文件]: {}", file.getAbsolutePath());
        //设置文件信息
        String absolutePath = file.getAbsolutePath().replaceAll("\\\\", "/");
        String time = String.valueOf(file.lastModified());
        String md5 = "";
        try {
            md5 = DigestUtils.md5Hex(new FileInputStream(file));
        } catch (IOException e) {
            e.printStackTrace();
        }
        String exist = "1";
        FileInfo fileinfo = new FileInfo(absolutePath, time, md5, exist);


        //根据路径生成info配置文件，路径不匹配则在根目录生成
        FileUtil fileUtil = FileUtil.getFileUtil();
        File infoFile = fileUtil.generateInfoFile(absolutePath);

        try {
            // 1. 读取配置文件
            FileMetaInfo metaInfo = FileUtil.readInfoFileToBean(infoFile);

            // 2. 判断是否有此配置文件

            List<FileInfo> changeFile = metaInfo.getChangeFile();
            if (changeFile == null) {//改变列表为空，添加第一条
                changeFile = new ArrayList<>();
                changeFile.add(fileinfo);
                metaInfo.setChangeFile(changeFile);
            } else {//改变不为空，寻找是否有，有的话，修改，没有添加
                boolean flag = false;
                for (int i = 0, length = changeFile.size(); i < length; i++) {
                    if (absolutePath.equals(changeFile.get(i).getPath())) {
                        changeFile.get(i).setPath(absolutePath);
                        changeFile.get(i).setTime(time);
                        changeFile.get(i).setHash(md5);
                        flag = true;
                        break;
                    }
                }
                if (!flag) {
                    changeFile.add(fileinfo);
                    metaInfo.setChangeFile(changeFile);
                }
            }

            removeCreateFile(absolutePath, metaInfo);

            removeDeleteFile(absolutePath, metaInfo);

            // 3. 修改并写入json文件

            String json = FastJsonUtils.convertObjectToJSON(metaInfo);
            FileUtils.write(infoFile, json, Charset.forName("utf-8"));


        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * /**
     * 文件删除
     */
    @Override
    public void onFileDelete(File file) {
        log.info("[删除文件]:" + file.getAbsolutePath());
        //设置文件信息
        String absolutePath = file.getAbsolutePath().replaceAll("\\\\", "/");
        String time = String.valueOf(file.lastModified());
        if (time.equals(0)) {
            time = String.valueOf(System.currentTimeMillis());
        }
        String md5 = "";
        try {
            md5 = DigestUtils.md5Hex(new FileInputStream(file));
        } catch (IOException e) {
            log.error(e.getMessage());
        }
        String exist = "1";
        FileInfo fileinfo = new FileInfo(absolutePath, time, md5, exist);

        //根据路径生成info配置文件，路径不匹配则在根目录生成
        FileUtil fileUtil = FileUtil.getFileUtil();
        File infoFile = fileUtil.generateInfoFile(absolutePath);
        String infoStr = null;
        try {
            // 1. 读取配置文件
            infoStr = FileUtils.readFileToString(infoFile, Charset.forName("utf-8"));
            FileMetaInfo metaInfo = (FileMetaInfo) FastJsonUtils.convertJSONToObject(infoStr, FileMetaInfo.class);

            if (metaInfo == null) {
                metaInfo = new FileMetaInfo();
            }

            // 2. 判断是否有此配置文件

            List<FileInfo> removeFile = metaInfo.getRemoveFile();
            if (removeFile == null) {//改变列表为空，添加第一条
                removeFile = new ArrayList<>();
                removeFile.add(fileinfo);
                metaInfo.setRemoveFile(removeFile);
            } else {//改变不为空，寻找是否有，有的话，修改，没有添加
                boolean flag = false;
                for (int i = 0, length = removeFile.size(); i < length; i++) {
                    if (absolutePath.equals(removeFile.get(i).getPath())) {
                        fileinfo.setPath(absolutePath);
                        fileinfo.setTime(time);
                        fileinfo.setHash(md5);
                        flag = true;
                        break;
                    }
                }
                if (!flag) {
                    removeFile.add(fileinfo);
                    metaInfo.setRemoveFile(removeFile);
                }
            }


            removeCreateFile(absolutePath, metaInfo);

            removeChangeFile(absolutePath, metaInfo);
            // 3. 修改并写入json文件

            String json = FastJsonUtils.convertObjectToJSON(metaInfo);
            FileUtils.write(infoFile, json, Charset.forName("utf-8"));


        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 目录创建
     */
    @Override
    public void onDirectoryCreate(File file) {
        log.info("[新建目录]:" + file.getAbsolutePath());
//        //设置文件信息
//        String absolutePath = file.getAbsolutePath().replaceAll("\\\\", "/");
//        String time = String.valueOf(file.lastModified());
//        FileInfo fileinfo = new FileInfo();
//        fileinfo.setPath(absolutePath);
//        fileinfo.setTime(time);
//
//        //根据路径生成info配置文件，路径不匹配则在根目录生成
//        FileUtil fileUtil = new FileUtil();
//        File infoFile = fileUtil.generateInfoFile(absolutePath);
//
//
//        String infoStr = null;
//        try {
//            // 1. 读取配置文件
//            infoStr = FileUtils.readFileToString(infoFile, Charset.forName("utf-8"));
//            FileMetaInfo metaInfo = (FileMetaInfo) FastJsonUtils.convertJSONToObject(infoStr, FileMetaInfo.class);
//
//            if (metaInfo == null) {
//                metaInfo = new FileMetaInfo();
//            }
//
//            // 2. 判断是否有此配置文件
//
//            List<FileInfo> createFile = metaInfo.getCreateFile();
//            if (createFile == null) {
//                createFile = new ArrayList<>();
//            }
//            createFile.add(fileinfo);
//            metaInfo.setCreateFile(createFile);
////            for (int i = 0, length = createFile.size(); i < length; i++) {
//////                if (absolutePath.equals(createFile.get(i))) { }
////                createFile.add(fileinfo);
////            }
//
//            List<FileInfo> changeFile = metaInfo.getChangeFile();
//            if (changeFile != null) {
//
//                Iterator<FileInfo> changeIterator = changeFile.iterator();
//                while (changeIterator.hasNext()) {
//                    if (absolutePath.equals(changeIterator.next().getPath())) {
//                        changeIterator.remove();
//                    }
//                }
//            }
//            List<FileInfo> removeFile = metaInfo.getRemoveFile();
//            if (removeFile != null) {
//                Iterator<FileInfo> removeIterator = removeFile.iterator();
//                while (removeIterator.hasNext()) {
//                    if (absolutePath.equals(removeIterator.next().getPath())) {
//                        removeIterator.remove();
//                    }
//                }
//            }
//            // 3. 修改并写入json文件
//
//            String json = FastJsonUtils.convertObjectToJSON(metaInfo);
//            FileUtils.write(infoFile, json, Charset.forName("utf-8"));
//
//
//        } catch (IOException e) {
//            e.printStackTrace();
//        }


    }

    /**
     * 目录修改
     */
    @Override
    public void onDirectoryChange(File file) {
        log.info("[修改目录]:" + file.getAbsolutePath());
//        //设置文件信息
//        String absolutePath = file.getAbsolutePath().replaceAll("\\\\", "/");
//
//        String time = String.valueOf(file.lastModified());
//        FileInfo fileinfo = new FileInfo();
//        fileinfo.setPath(absolutePath);
//        fileinfo.setTime(time);
//
//        //根据路径生成info配置文件，路径不匹配则在根目录生成
//        FileUtil fileUtil = new FileUtil();
//        File infoFile = fileUtil.generateInfoFile(absolutePath);
//
//        String infoStr = null;
//        try {
//            // 1. 读取配置文件
//            infoStr = FileUtils.readFileToString(infoFile, Charset.forName("utf-8"));
//            FileMetaInfo metaInfo = (FileMetaInfo) FastJsonUtils.convertJSONToObject(infoStr, FileMetaInfo.class);
//
//            if (metaInfo == null) {
//                metaInfo = new FileMetaInfo();
//            }
//
//            // 2. 判断是否有此配置文件
//
//            List<FileInfo> changeFile = metaInfo.getChangeFile();
//            if (changeFile == null) {//改变列表为空，添加第一条
//                changeFile = new ArrayList<>();
//                changeFile.add(fileinfo);
//                metaInfo.setCreateFile(changeFile);
//            } else {//改变不为空，寻找是否有，有的话，修改，没有添加
//                boolean flag = false;
//                for (int i = 0, length = changeFile.size(); i < length; i++) {
//                    if (absolutePath.equals(changeFile.get(i))) {
//                        fileinfo.setPath(absolutePath);
//                        fileinfo.setTime(time);
//                        flag = true;
//                        break;
//                    }
//                }
//                if (!flag) {
//                    changeFile.add(fileinfo);
//                    metaInfo.setChangeFile(changeFile);
//                }
//            }
//
//
//            List<FileInfo> createFile = metaInfo.getCreateFile();
//            if (createFile != null) {
//
//                Iterator<FileInfo> createIterator = createFile.iterator();
//                while (createIterator.hasNext()) {
//                    if (absolutePath.equals(createIterator.next().getPath())) {
//                        createIterator.remove();
//                    }
//                }
//            }
//            List<FileInfo> removeFile = metaInfo.getRemoveFile();
//            if (removeFile != null) {
//                Iterator<FileInfo> removeIterator = removeFile.iterator();
//                while (removeIterator.hasNext()) {
//                    if (absolutePath.equals(removeIterator.next().getPath())) {
//                        removeIterator.remove();
//                    }
//                }
//            }
//            // 3. 修改并写入json文件
//
//            String json = FastJsonUtils.convertObjectToJSON(metaInfo);
//            FileUtils.write(infoFile, json, Charset.forName("utf-8"));
//
//
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
    }

    /**
     * 目录删除
     */
    @Override
    public void onDirectoryDelete(File file) {
        log.info("[删除文件]:" + file.getAbsolutePath());
//        //设置文件信息
//        String absolutePath = file.getAbsolutePath().replaceAll("\\\\", "/");
//        String time = String.valueOf(file.lastModified());
//        if (time.equals(0)) {
//            time = String.valueOf(System.currentTimeMillis());
//        }
//        FileInfo fileinfo = new FileInfo();
//        fileinfo.setPath(absolutePath);
//        fileinfo.setTime(time);
//
//        //根据路径生成info配置文件，路径不匹配则在根目录生成
//        FileUtil fileUtil = new FileUtil();
//        File infoFile = fileUtil.generateInfoFile(absolutePath);
//        String infoStr = null;
//        try {
//            // 1. 读取配置文件
//            infoStr = FileUtils.readFileToString(infoFile, Charset.forName("utf-8"));
//            FileMetaInfo metaInfo = (FileMetaInfo) FastJsonUtils.convertJSONToObject(infoStr, FileMetaInfo.class);
//
//            if (metaInfo == null) {
//                metaInfo = new FileMetaInfo();
//            }
//
//            // 2. 判断是否有此配置文件
//
//            List<FileInfo> removeFile = metaInfo.getRemoveFile();
//            if (removeFile == null) {//改变列表为空，添加第一条
//                removeFile = new ArrayList<>();
//                removeFile.add(fileinfo);
//                metaInfo.setRemoveFile(removeFile);
//            } else {//改变不为空，寻找是否有，有的话，修改，没有添加
//                boolean flag = false;
//                for (int i = 0, length = removeFile.size(); i < length; i++) {
//                    if (absolutePath.equals(removeFile.get(i))) {
//                        fileinfo.setPath(absolutePath);
//                        fileinfo.setTime(time);
//                        flag = true;
//                        break;
//                    }
//                }
//                if (!flag) {
//                    removeFile.add(fileinfo);
//                    metaInfo.setRemoveFile(removeFile);
//                }
//            }
//
//
//            List<FileInfo> createFile = metaInfo.getCreateFile();
//            if (createFile != null) {
//
//                Iterator<FileInfo> createIterator = createFile.iterator();
//                while (createIterator.hasNext()) {
//                    if (absolutePath.equals(createIterator.next().getPath())) {
//                        createIterator.remove();
//                    }
//                }
//            }
//            List<FileInfo> changeFile = metaInfo.getChangeFile();
//            if (changeFile != null) {
//                Iterator<FileInfo> changeIterator = changeFile.iterator();
//                while (changeIterator.hasNext()) {
//                    if (absolutePath.equals(changeIterator.next().getPath())) {
//                        changeIterator.remove();
//                    }
//                }
//            }
//            // 3. 修改并写入json文件
//
//            String json = FastJsonUtils.convertObjectToJSON(metaInfo);
//            FileUtils.write(infoFile, json, Charset.forName("utf-8"));
//
//
//        } catch (IOException e) {
//            e.printStackTrace();
//        }

    }

    @Override
    public void onStart(FileAlterationObserver observer) {
        // TODO Auto-generated method stub
        super.onStart(observer);
    }

    @Override
    public void onStop(FileAlterationObserver observer) {
        // TODO Auto-generated method stub
        super.onStop(observer);
    }





    public void removeCreateFile(String absolutePath, FileMetaInfo metaInfo) {
        List<FileInfo> createFile = metaInfo.getCreateFile();
        if (createFile != null) {

            Iterator<FileInfo> createIterator = createFile.iterator();
            while (createIterator.hasNext()) {
                if (absolutePath.equals(createIterator.next().getPath())) {
                    createIterator.remove();
                }
            }
        }
    }


    public void removeChangeFile(String absolutePath, FileMetaInfo metaInfo) {
        // 监控文件创建时移除改变列表中的文件
        List<FileInfo> changeFile = metaInfo.getChangeFile();
        if (changeFile != null) {
            Iterator<FileInfo> changeIterator = changeFile.iterator();
            while (changeIterator.hasNext()) {
                if (absolutePath.equals(changeIterator.next().getPath())) {
                    changeIterator.remove();
                }
            }
        }
    }

    public void removeDeleteFile(String absolutePath, FileMetaInfo metaInfo) {
        // 移除删除列表
        List<FileInfo> removeFile = metaInfo.getRemoveFile();
        if (removeFile != null) {
            Iterator<FileInfo> removeIterator = removeFile.iterator();
            while (removeIterator.hasNext()) {
                if (absolutePath.equals(removeIterator.next().getPath())) {
                    removeIterator.remove();
                }
            }
        }
    }

    public void startMonitor(String rootDir) throws Exception {

        // 1. 开始监控dir 目录，生成info目录
        File file = new File(rootDir + File.separator + "info.json");
        if (!file.exists()) {
            file.createNewFile();
        }

        // 轮询间隔 5 秒
        long interval = TimeUnit.SECONDS.toMillis(1);

        // 创建过滤器  目录过滤器
        IOFileFilter directories = FileFilterUtils.and(FileFilterUtils.directoryFileFilter(), HiddenFileFilter.VISIBLE);
        // 文件过滤器
        IOFileFilter files = FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter("info.json"));
//        目录和文件结合
        IOFileFilter filter = FileFilterUtils.or(directories, files);

        // 使用过滤器
        FileAlterationObserver observer = new FileAlterationObserver(new File(rootDir), filter);
        //添加监听
        observer.addListener(new FileListener());
        //创建文件变化监听器
        FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);
        // 开始监控
        monitor.start();

    }

    public static void main(String[] args) throws Exception {


        // 监控目录
        String rootDir = "D:\\SFTP";
//        File file = new File(rootDir + File.separator + "info.json");
//        if (!file.exists()) {
//            file.createNewFile();
//        }
//        // 轮询间隔 5 秒
        long interval = TimeUnit.SECONDS.toMillis(1);
        // 创建过滤器  目录过滤器
        IOFileFilter directories = FileFilterUtils.and(FileFilterUtils.directoryFileFilter(), HiddenFileFilter.VISIBLE);
        // 文件过滤器
//        IOFileFilter files = FileFilterUtils.and(FileFilterUtils.fileFileFilter(), FileFilterUtils.suffixFileFilter(".json"));
        IOFileFilter files = FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter("info.json"));
//        IOFileFilter files = FileFilterUtils.and(FileFilterUtils.fileFileFilter());

//        目录和文件结合
        IOFileFilter filter = FileFilterUtils.or(directories, files);
        // 使用过滤器
        FileAlterationObserver observer = new FileAlterationObserver(new File(rootDir), filter);
        //不使用过滤器
//        FileAlterationObserver observer = new FileAlterationObserver(new File(rootDir));
        observer.addListener(new FileListener());
        //创建文件变化监听器
        FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);
        // 开始监控
        monitor.start();


    }

}

